package nl.vu.few.ibivu.biomodels.server.petrinet;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.ListIterator;
import java.util.NoSuchElementException;

public class CombinationsIterator implements ListIterator<List<Integer>> {

	int listLength;
	int maxValue;
	ArrayList<Integer> current;
	double total;
	double idx;
	
	public CombinationsIterator(int maxValue, int listLength, boolean reverse) {
		super();
		this.listLength = listLength;
		this.maxValue = maxValue;
		total = Math.pow(maxValue + 1, listLength);
		current = new ArrayList<Integer>(listLength);
		current.addAll(Collections.nCopies(listLength, (reverse) ? 0 : maxValue));
		idx = (reverse) ? total : 0;
	}
	
	public CombinationsIterator(int maxValue, int listLength) {
		this(maxValue, listLength, false);
	}


	private void add1() {
		ListIterator<Integer> iterator = current.listIterator(current.size());
		int value = 0;
		while (iterator.hasPrevious()) {
			iterator.set(value = ((iterator.previous() + 1) % (maxValue + 1)));
			if (value > 0) break;
		}
	}
	
	private void sub1() {
		ListIterator<Integer> iterator = current.listIterator(current.size());
		while (iterator.hasPrevious()) {
			int value;
			iterator.set(((value = iterator.previous()) == 0) ? maxValue : value - 1);
			if (value > 0) break;
		}
	}
	
	@Override
	public void add(List<Integer> arg0) {
		throw new UnsupportedOperationException();
	}

	@Override
	public boolean hasNext() {
		return idx < total;
	}

	@Override
	public boolean hasPrevious() {
		return idx > 0;
	}

	@Override
	public List<Integer> next() {
		if (!hasNext()) {
			throw new NoSuchElementException();
		}
		add1();
		idx++;
		return current;
	}

	@Override
	public int nextIndex() {
		return (int)idx + 1;
	}

	@Override
	public List<Integer> previous() {
		if (!hasPrevious()) {
			throw new NoSuchElementException();
		}
		sub1();
		idx--;
		return current;
	}

	@Override
	public int previousIndex() {
		return (int)idx - 1;
	}

	@Override
	public void remove() {
		throw new UnsupportedOperationException();
		
	}

	@Override
	public void set(List<Integer> arg0) {
		throw new UnsupportedOperationException();
	}

	public int getTotal() {
		return (int)total;
	}
}
